package com.tamir.template.util;

import com.tamir.template.bean.IntermediateOperator;
import com.tamir.template.bean.LogicOperate;
import com.tamir.template.bean.TNode;
import com.tamir.template.config.OperatorConfig;
import com.tamir.template.exception.TemplateException;

import java.math.BigDecimal;
import java.util.Stack;

/**
 * @author : tanggh
 * @description : 操作符工具类
 * @date : 2017/1/3
 */
public class OperaterUtil
{
    /**
     * 判断操作符是否合法
     * 操作符后边只能跟数字、字母、(、_否则认为不合法
     *
     * @param ch
     * @return
     */
    public static boolean judgeOperatorIsLegal(char ch){
        if((ch >= 97 && ch <= 122)|| (ch>=65 && ch <= 90) || (ch >= 48 && ch <= 57) || ch == '_' ||
                ch == '('){
            return true;
        }
        return false;
    }

    /**
     * 生成逻辑操作对象
     * @param operator
     * @param valueStack
     */
    public static void genLogicOperator(IntermediateOperator operator,
                                        Stack<Object> valueStack){
        if(operator.isOperator()){
            if(operator.getExpress().equals(String.valueOf(OperatorConfig.non))){
                Object valueObject = getLogicOperator(operator, valueStack);;
                LogicOperate logicOperate = getLogicOperator(valueObject);
                logicOperate.setNon(true);
                valueStack.push(logicOperate);
            }else {
                //先推出来的放右边(减法和除法严格区分)
                Object rightObj = getLogicOperator(operator, valueStack);
                //后推出来的放左边
                Object leftObj = getLogicOperator(operator, valueStack);
                LogicOperate logicOperate = new LogicOperate();
                logicOperate.setExpress(operator.getExpress());
                logicOperate.setOperator(operator.getExpress());
                logicOperate.setLeftOperate(getLogicOperator(leftObj));
                logicOperate.setRightOperate(getLogicOperator(rightObj));
                valueStack.push(logicOperate);
            }
        }else{
            valueStack.push(operator);
        }
    }

    /**
     * 从中间生成操作符生成逻辑操作符对象
     * @param obj
     * @return
     */
    public static LogicOperate getLogicOperator(Object obj){
        LogicOperate retLO = null;
        if(obj != null){
            if(obj instanceof IntermediateOperator){
                retLO = new LogicOperate();
                retLO.setExpress(((IntermediateOperator) obj).getExpress());
            }else{
                retLO = (LogicOperate)obj;
            }
        }
        return retLO;
    }

    /**
     * 获取值堆栈中的值不能为空,为空则认为表达式语法有误
     * @param operator
     * @param valueStack
     * @return
     */
    public static Object getLogicOperator(IntermediateOperator operator, Stack<Object> valueStack){
        if(valueStack.isEmpty()){
            throw new TemplateException("", "syntax error:"+operator.getExpress()+" mismatch the"+
                    " number of variables");
        }
        return valueStack.pop();
    }

    /**
     * 判断当前字符和下一个字符并返回操作符
     * @param cur
     * @param next
     * @return
     */
    public static String judgeOperator(char cur, char next){
        StringBuffer operator = new StringBuffer();
        operator.append(cur);
        switch (cur){
            case '=':
                operator.append(next);
                if(next != OperatorConfig.eq){
                    throw new TemplateException("", "not supported operator:" + operator.toString
                            ());
                }
                break;
            case '>':
                if(next == OperatorConfig.eq){
                    operator.append(next);
                }else{
                    if(!OperaterUtil.judgeOperatorIsLegal(next)){
                        operator.append(next);
                        throw new TemplateException("", "error happen:" + operator
                                .toString
                                        ());
                    }
                }
                break;
            case '<':
                if(next == OperatorConfig.eq || next == OperatorConfig.gt){
                    operator.append(next);
                }else{
                    OperaterUtil.operateIsLegal(next, operator);
                }
                break;
            case '!':
                if(next == OperatorConfig.eq){
                    operator.append(next);
                }else if(next == OperatorConfig.leftBracket){

                }else{
                    OperaterUtil.operateIsLegal(next, operator);
                }
                break;
            case '&':
                if(next == OperatorConfig.and){
                    operator.append(next);
                }else{
                    OperaterUtil.operateIsLegal(next, operator);
                }
                break;
            case '|':
                if(next == OperatorConfig.or){
                    operator.append(next);
                }else{
                    OperaterUtil.operateIsLegal(next, operator);
                }
                break;
            default:
                break;

        }
        if(cur == '+' || cur == '-' || cur == '*' || cur == '/'){
            if(!OperaterUtil.judgeOperatorIsLegal(next)){
                throw new TemplateException("", "error happen:" + operator
                        .toString
                                ());
            }
        }
        return operator.toString();
    }

    /**
     * 操作符不合法抛出异常
     * @param next
     * @param operator
     */
    public static void operateIsLegal(char next, StringBuffer operator){
        if(!OperaterUtil.judgeOperatorIsLegal(next)){
            operator.append(next);
            throw new TemplateException("", "error happen:" + operator
                    .toString
                            ());
        }
    }
    /**
     * 放入新的逻辑操作符
     * @param stack
     */
    public static void pushNewLogicOperate(Stack<LogicOperate> stack){
        LogicOperate logicOperate = new LogicOperate();
        if(stack.isEmpty()){
            stack.push(logicOperate);
        }else{
            stack.peek().setRightOperate(logicOperate);
            stack.push(logicOperate);
        }
    }

    /**
     * 计算值
     * @param operator 操作符
     * @param leftObj  操作符左边的值
     * @param rightObj 操作符右边的值
     * @param node  当前结点
     * @param operate 当前操作符对象
     * @return
     */
    public static Object calObject(String operator, Object leftObj, Object rightObj, TNode node,
                                   LogicOperate operate){
        Object obj = null;
        if("+-*/".contains(operator)){
            checkExpressValue(leftObj, node, operate.getLeftOperate());
            checkExpressValue(rightObj, node, operate.getRightOperate());
            obj = calculateObj(operator, leftObj, rightObj);
            return obj;
        }
        Boolean retObj = false;
        if("==".equalsIgnoreCase(operator)){
            retObj = eqObject(leftObj, rightObj);
        }else if("!=".equalsIgnoreCase(operator)){
            retObj = !eqObject(leftObj, rightObj);
        }else if(">".equalsIgnoreCase(operator)){
            retObj = gtObject(leftObj, rightObj);
        }else if("<".equalsIgnoreCase(operator)){
            retObj = ltObject(leftObj, rightObj);
        }else if(">=".equalsIgnoreCase(operator)){
            retObj = !ltObject(leftObj, rightObj);
        }else if("<=".equalsIgnoreCase(operator)){
            retObj = !gtObject(leftObj, rightObj);
        }else if("&&".equalsIgnoreCase(operator)){
            retObj =  andObject(leftObj, rightObj);
        }else if("||".equalsIgnoreCase(operator)){
            retObj = orObject(leftObj, rightObj);
        }
        return retObj;
    }

    /**
     * 校验当前值不能为空
     * @param object
     * @param node
     * @param operate
     * @throws Exception
     */
    private static void checkExpressValue(Object object, TNode node, LogicOperate operate){
        if(object == null){
            String fullExpress = operate.getExpress();
            if(node != null){
                fullExpress = node.getRealExpress();
            }
            throw new RuntimeException("express:"+fullExpress + ", variable '"+operate.getExpress() +"' " +
                    "can't be null");
        }
    }


    /**
     * 与运算
     * null当做false处理
     * 除了boolean类型其它当作true处理
     * @param leftObj
     * @param rightObj
     * @return
     */
    public static Boolean andObject(Object leftObj, Object rightObj){
        Boolean judgeResult = judgeObject(leftObj, rightObj, OperatorConfig.and);
        if(judgeResult != null){
            return judgeResult;
        }
        return leftObj != null && rightObj != null;
    }

    /**
     * 或运算
     * null当做false处理
     * 除了boolean类型其它当作true处理
     * @param leftObj
     * @param rightObj
     * @return
     */
    public static Boolean orObject(Object leftObj, Object rightObj){
        Boolean judgeResult = judgeObject(leftObj, rightObj, OperatorConfig.or);
        if(judgeResult != null){
            return judgeResult;
        }
        //只要有一个不为null,返回true
        return leftObj != null || rightObj != null;
    }

    /**
     * == 运算
     * @param leftObj
     * @param rightObj
     * @return
     */
    public static Boolean eqObject(Object leftObj, Object rightObj)
    {
        //如果leftObj和rightObj都为null或者同一个对象返回true
        if(leftObj == rightObj){
            return Boolean.TRUE;
        }
        //上边判断过两个都为null的情况了,接下来只要有一个为null返回false
        if(leftObj == null || rightObj == null){
            return Boolean.FALSE;
        }
        Boolean judgeResult = judgeObject(leftObj, rightObj, OperatorConfig.eq);
        if(judgeResult == null){
            if(leftObj instanceof BigDecimal && rightObj instanceof BigDecimal){
                return ((BigDecimal) leftObj).compareTo((BigDecimal)rightObj) == 0;
            }else{
                return leftObj.equals(rightObj);
            }
        }else{
            return judgeResult;
        }

    }

    /**
     * 小于
     * @param leftObj
     * @param rightObj
     * @return
     */
    public static Boolean ltObject(Object leftObj, Object rightObj)
    {
        if(leftObj instanceof BigDecimal && rightObj instanceof BigDecimal){
            return ((BigDecimal) leftObj).compareTo((BigDecimal)rightObj) < 0;
        }else{
            return leftObj.equals(rightObj);
        }
    }

    /**
     * 大于
     * @param leftObj
     * @param rightObj
     * @return
     */
    public static Boolean gtObject(Object leftObj, Object rightObj)
    {
        if(leftObj instanceof BigDecimal && rightObj instanceof BigDecimal){
            return ((BigDecimal) leftObj).compareTo((BigDecimal)rightObj) > 0;
        }else{
            return leftObj.equals(rightObj);
        }
    }

    /**
     * 根据操作符计算值
     * @param operator
     * @param leftObj
     * @param rightObj
     * @return
     */
    public static Object calculateObj(String operator, Object leftObj, Object rightObj){
        Object retObj = new BigDecimal(0);
        BigDecimal lObj = new BigDecimal(leftObj.toString());
        BigDecimal rObj = new BigDecimal(rightObj.toString());
        if("+".equalsIgnoreCase(operator)){
            retObj = lObj.add(rObj);
        }else if("-".equalsIgnoreCase(operator)){
            retObj = lObj.subtract(rObj);//上边要把减数放在右边
        }else if("*".equalsIgnoreCase(operator)){
            retObj = lObj.multiply(rObj);
        }else if("/".equalsIgnoreCase(operator)){
            retObj = lObj.divide(rObj, OperatorConfig.getInstance().getDivideScale(),
                    OperatorConfig.getInstance().getRoundingMode());
        }
        return retObj;
    }
    //转boolean,除Boolean、"true"、"false",其它类型不做处理为null
    public static Boolean toBoolean(Object object){
        if(object == null){
            return null;
        }
        if(object instanceof Boolean){
            return (Boolean)object;
        }
        if(object instanceof String && (Boolean.TRUE.toString().equalsIgnoreCase(object.toString()) ||
                Boolean.FALSE.toString()
                        .equalsIgnoreCase(object.toString()))){
            return new Boolean(object.toString());
        }
        return null;
    }
    //比较两个对象, 不对null处理
    public static Boolean judgeObject(Object leftObj, Object rightObj, char judge){
        Boolean left = toBoolean(leftObj);
        Boolean right = toBoolean(rightObj);
        if(left != null && right != null){
            if(judge == OperatorConfig.eq){
                return left.booleanValue() == right.booleanValue();
            }else if(judge == OperatorConfig.and){
                return left.booleanValue() && right.booleanValue();
            }else {
                return left.booleanValue() || right.booleanValue();
            }
        }
        return null;
    }

    public static void main(String[] args)
    {
        System.out.println(new BigDecimal("400.0").toString());
    }
}
